AddCSLuaFile("cl_init.lua") 
AddCSLuaFile("shared.lua") 
include('shared.lua')

ENT.KeyTriggerInformation = {}

function ENT:Initialize() 
	self.NumPaths = 0	
	self.PathTable = {}
	self:SetNWInt("VarNumPaths", 0)
	self:SetNWInt("VarPathEntID", -1)
		 
	self:SetNWInt("show_view_finder", 0)

	self:SetNWString("framing_type", "nil")
	
	self.RangeEndpoint = false
	self.BaseClass.Initialize(self, Model("models/dav0r/camera.mdl"))
end

function ENT:ShowViewFinder()

print("Calling: function ENT:ShowViewFinder()")
	local playerIdx = self.BaseClass.GetPlayerIndex(self)
	local trackIdx = self.BaseClass.GetTrackIndex(self)
	local numTrackNodes = #CatmullRomCams.Tracks[playerIdx][trackIdx]

	for i = 1, numTrackNodes do
		if CatmullRomCams.Tracks[playerIdx][trackIdx][i] then
			CatmullRomCams.Tracks[playerIdx][trackIdx][i]:SetNWInt("show_view_finder", 0)
		end
	end

	print("setting view finder")

	self:SetNWInt("show_view_finder", 1)
	self:GetNWInt("duration_wait", 0)
end

//
//function ENT:CheckTriggerEvents(segmentIndex)
//
//		local ent = CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key][segmentIndex]
//		if ent.PathNodes  && ent.PathNodes:IsValid() then
//			print("  Found path node -> Invoking PlayActors()")
//			ent.PathNodes:PlayActors(SCHED_FORCED_GO)
//		end
//
//end
//
//function ENT:AssignPathNode(pathnode)
//
//	if (pathnode && pathnode:IsValid()) then 
//	
//		self.PathNodes = pathnode
//		print("Assigned self.PathNodes")
//	else
//		print("Bad path node")
//	end
//end
//
//function ENT:UnassignPathNode(npc)
//
//		print("UnassignPathNode got called")
//end


//****************************************************
//*	Called externally to assign an actor pathway to this
//* node on the camera track. Returns true if successful
function ENT:AssignActorPathwayToTrack(actorPathway)
		
	if not self.BaseClass.IsPathNode(self, actorPathway) then
		return false
	end

	self.NumPaths = self.NumPaths + 1	
	self.PathTable[actorPathway:EntIndex()] = actorPathway
	self:SetNWInt("VarNumPaths", self.NumPaths)
	self:SetNWInt("VarPathEntID", actorPathway:EntIndex())

	 print("Assigned ", self.NumPaths)
	 print("Node ID:" ,self.BaseClass.GetNodeIndex(self))
	return true
end

//****************************************************
//* Called internally, this function checks to see if 
//* there are any 'actor walking pathways' that have been
//* assigned to it. If any are discovered, they are
//* executed to cause respective actors to walk along 
//* those tracks
function ENT:ThinkActorPathways()

//print("function ENT:ThinkActorPathways()", self.BaseClass.GetNodeIndex(self))
//print("paths = ", self.PathTable)
//print("num paths = ", self.NumPaths)
	if (not self.PathTable) or self.NumPaths == 0 then
		return
	end
print("itterating...")
	for k, actorPathNode in pairs(self.PathTable) do
		if self.BaseClass.IsPathNode(self, actorPathNode) then

			//Acording to this functions documentation
			//it is safe to call this function on any node
			//on the pathway track
			print("playing...")
			actorPathNode:PlayActors(0)

		end
	end

end

function ENT:ClearHighlighting()

	local numCameras = #CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key]
	for i = 1, numCameras do

		local nodeCamera = CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key][i]:GetNWEntity("ChildCamera")
		if(nodeCamera != nil) then
			nodeCamera:SetNWBool("IsHighlighted", false)
		end
	end

end

function ENT:UpdateHighlighting()

	local numCameras = #CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key]
	for i = 1, numCameras do
	
		local stateValue = false
		if(i >= RangeStart && i <= RangeEnd) then
			stateValue = true
		elseif (RangeStart == i && RangeStart != -1) then
			stateValue = true
		elseif (RangeEnd == i && RangeEnd != -1) then
			stateValue = true
		end

		local nodeCamera = CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key][i]:GetNWEntity("ChildCamera")
		if(nodeCamera != nil) then
			nodeCamera:SetNWBool("IsHighlighted", stateValue)
		end
	end

end

function ENT:SetRangeEndpoint(range)

	//If none defined or both defined
	if (RangeStart == -1) && (RangeEnd == -1) || (RangeStart != -1) && (RangeEnd != -1) then
		//Just set a range
		RangeStart = range
		RangeEnd = -1;
	else
		//Only the start is undefined
		if( RangeStart == -1) then
		//{
			//Assume range end is assigned
			if (range > RangeEnd) then 
				RangeStart = RangeEnd
				RangeEnd = range
			//If the range is less than that start, assign as usual
			elseif (range < RangeEnd) then
				RangeStart = range
			else
			//This case indicates the same node was clicked - should never execute
			end
		//}
		//Only the end is undefined
		elseif (RangeEnd == -1) then
		//{
			//Assume the usual case
			if (range > RangeStart) then
				RangeEnd = range
			//If the order was out
			elseif (range < RangeStart) then
				RangeEnd = RangeStart
				RangeStart = range
			else
			//Bad case
			end
		else
			//Bad case
		end	
	end

	self:UpdateHighlighting()

end

function ENT:ToggleHighlighted()
	if SERVER then

		if not CatmullRomCams.Tracks then 
			print("No data!")
			return
		end

	local numPoints = #CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key]
		for i = 1, numPoints do
			
			local nodeCamera = CatmullRomCams.Tracks[self.UndoData.PID][self.UndoData.Key][i]:GetNWEntity("ChildCamera")
			if self == nodeCamera then
				
				self:SetRangeEndpoint(i)
				return
			end
		end
	end
end

function ENT:Think()

	if self.IsMapController then return end


	local masterController = self:GetNWEntity("MasterController")
	if masterController and masterController.Playing then

	end

	if self:GetNWBool("IsMasterController") then
		if self.Playing and self.ViewPointEnt then
			self:GetPointData()
		local playerIndex = self.BaseClass.GetPlayerIndex(self)
		local trackIndex = self.BaseClass.GetTrackIndex(self)

		for key,node in pairs(CatmullRomCams.Tracks[playerIndex][trackIndex]) do

			local viewPointPosition = self.ViewPointEnt:GetPos()
			local nodePosition = node:GetPos()
			if viewPointPosition:Distance(nodePosition) < 10 then
				node:ThinkActorPathways()
				break
			end

		end


			//self:ThinkActorPathways()
			
			if #self.CatmullRomController.PointsList < 4 then
				self.ViewPointEnt:Remove()
				
				self.Playing = false
				self:SetNWBool("IsPlaying", false)
			end
		end
	end

	self.Entity:NextThink(CurTime())
end

////////////////////////////////////////////////
//Called on the server. Will look to see if a
//camera range has been defined and then override
//the camera accordingly
//
function ENT:CheckOutsideRange(segmentIndex)
	
	if(RangeStart != -1 && RangeEnd != -1) then
		if (segmentIndex < RangeStart) then
			self.CatmullRomController.CurSegment = RangeEnd
		elseif(segmentIndex > RangeEnd) then
			self.CatmullRomController.CurSegment = RangeStart + 1
		end
	end	

end


function ENT:OnChangeSegment(segment)

	print("Changing on camera track...")
	self:ThinkActorPathways()
	//self:CheckOutsideRange(segment)
	//self:CheckTriggerEvents(segment)

	if ent and ent:IsValid() and ent.OnNodeTriggerNumPadKey then
		local ply    = self:GetNetworkedEntity("ControllingPlayer")
		
		self:InternalQuickToggleNumpad(ent.OnNodeTriggerNumPadKey.Keys, ply, ply:UniqueID())
		
		if not ent.OnNodeTriggerNumPadKey.Hold then
			return timer.Simple(.25, self.InternalQuickToggleNumpad, self, ent.OnNodeTriggerNumPadKey.Keys, ply, ply:UniqueID())
		end
	end
end

function ENT:InternalQuickToggleNumpad(keys, ply, plyid)
	for _, key in pairs(keys) do
		if self.KeyTriggerInformation[key] then
			numpad.Deactivate(ply, nil, {key}, plyid) -- Stupid numpad lib needs this as a table ):<
		else
			numpad.Activate(ply, nil, {key}, plyid)
		end
		
		self.KeyTriggerInformation[key] = not self.KeyTriggerInformation[key]
	end
end

function ENT:PhysicsUpdate(physobj)
	if not self.Entity:IsPlayerHolding() then
		if self.IsMapController then
			physobj:EnableMotion(false)
		else
			physobj:Sleep()
		end
	end
end

function ENT:LoadForMap(filename)
	filename = filename or ""

	self:SetCollisionGroup(COLLISION_GROUP_NONE)
	self:SetMoveType(MOVETYPE_NONE)
	self:SetSolid(SOLID_NONE)
	
	self.IsMapController = true
	self:SetNWBool("IsMapController", true)
	
	if not CatmullRomCams then
		include("autorun/sh_CatmullRomCams")
	end
	
	self:InitController()
	
	local data = file.Read("CatmullRomCameraTracks/" .. filename .. ".txt")
	
	if not data then return Error("Could not load filename track '" .. filename .. "' from disk! " .. tostring(self) .. " map controller will not work!!!\n") end
	
	data = util.KeyValuesToTable(data)
	
	for k, v in ipairs(data) do
	end
	
	local lastent = self
	local count = 1
	
	self.CatmullRomController.PointsList = {}
	self.CatmullRomController.AnglesList = {}
	
	self.CatmullRomController.DurationList = {}
	
	self.CatmullRomController.Spline = {}
	
	self.CatmullRomController:AddPointAngle(count, lastent:GetPos(), lastent:GetAngles())
	
	while true do
		count = count + 1
		
		local ent = lastent:GetNWEntity("ChildCamera")
		
		if ent and ent:IsValid() then
			lastent = ent
			
			local dur = lastent:GetNWFloat("Duration")
			
			self.CatmullRomController:AddPointAngle(count, lastent:GetPos(), lastent:GetAngles(), (dur > 0) and dur or 2)
			
			self.CatmullRomController.EntityList[count] = lastent
		else
			break
		end
	end
end

function ENT:KeyValue(k, v)
	if k == "TrackFilename" then
		return self:LoadForMap(v)
	end
end

function ENT:PreEntityCopy() -- build the DupeInfo table and save it as an entity mod
	return duplicator.StoreEntityModifier(self.Entity, "CatmullRomCamsDupData", self:RequestSaveData())
end

function ENT:PostEntityPaste(Player, Ent, CreatedEntities)
	local plyID = Player:UniqueID()
	
	if Ent.EntityMods and Ent.EntityMods.CatmullRomCamsDupData then
		--[[
		if not CatmullRomCams.Tracks[plyID][Ent.EntityMods.CatmullRomCamsDupData.UndoData.Key].IsLockedForLoad then  -- hackz
			for k, v in pairs(CatmullRomCams.Tracks[plyID][Ent.EntityMods.CatmullRomCamsDupData.UndoData.Key]) do
				if v and v:IsValid() then
					v:Remove()
				end
			end
			
			CatmullRomCams.Tracks[plyID][Ent.EntityMods.CatmullRomCamsDupData.UndoData.Key] = {}
			CatmullRomCams.Tracks[plyID][Ent.EntityMods.CatmullRomCamsDupData.UndoData.Key].IsLockedForLoad = true
		end
		--]]
		return CatmullRomCams.SV.AdvDupPaste(self, Player, plyID, Ent, CreatedEntities)
	else
		self:Remove()
	end
end

function ENT:BuildDupeInfo()
end

function ENT:ApplyDupeInfo(ply, ent, data, CreatedEntities)
end

function ENT.AfterPasteMods(ply, Ent, DupeInfo) -- Happens before PostEntityPaste for some reason <_<
end
duplicator.RegisterEntityModifier("CatmullRomCamsDupData", ENT.AfterPasteMods)
